package com.google.code.mergeinformer.controller;

import com.google.code.mergeinformer.util.AppUtils;
import com.google.code.mergeinformer.util.ServletUtils;
import org.apache.commons.io.IOUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringWriter;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import static org.springframework.http.MediaType.TEXT_PLAIN_VALUE;

/**
 * @author Dmitry Golubev
 */
@Controller
public class ResourceController {

    private static final String MESSAGES_DIR = "/resources/msg/";
    private static final String JS_DIR = "/resources/js/";
    private static final String CSS_DIR = "/resources/css/";

    private static final int CACHE_TTL = AppUtils.getPropertyInt("app.resources.cacheSeconds");

    private static final Pattern messageFileNamePattern = Pattern.compile("(?i)(^.*?_[a-z]{2}).*$");

    @Autowired
    private HttpServletRequest request;

    @RequestMapping(value = "/resources/msg/{file:.+}.properties", produces = TEXT_PLAIN_VALUE)
    public @ResponseBody String getLocalizedMessages(@PathVariable String file, HttpServletResponse response) throws IOException {
        // drop country and variant suffixes
        final Matcher matcher = messageFileNamePattern.matcher(file);
        if (matcher.matches()) {
            file = matcher.group(1);
        }
        // drop _en suffix since it is default language
        final String resourcePath = MESSAGES_DIR + file.replaceAll("(?i)_en$", "") + ".properties";
        try (InputStream resourceAsStream = request.getSession().getServletContext().getResourceAsStream(resourcePath)) {
            if (resourceAsStream == null) {
                throw new NoSuchResourceException();
            }

            final StringWriter content = new StringWriter();
            IOUtils.copy(resourceAsStream, content);
            setCacheHeaders(response);
            return content.toString();
        }
    }

    /**
     * Controller method for loading JavaScript files. If environment is prod, method returns compressed version of
     * script or uncompressed if no compressed version is available.
     */
    @RequestMapping(value = "/resources/js/{scriptName:.+}.js")
    public @ResponseBody String getJavaScript(@PathVariable String scriptName, HttpServletResponse response) throws IOException {
        final String resourcePath = getSourcePath(JS_DIR, scriptName, "js");
        try (InputStream resourceAsStream = request.getSession().getServletContext().getResourceAsStream(resourcePath)) {
            if (resourceAsStream == null) {
                throw new NoSuchResourceException();
            }

            final StringWriter content = new StringWriter();
            IOUtils.copy(resourceAsStream, content);
            setCacheHeaders(response);
            return content.toString();
        }
    }

    /**
     * Controller method for loading css files. If environment is prod, method returns compressed version of
     * css or uncompressed if no compressed version is available.
     */
    @RequestMapping(value = "/resources/css/{cssName:.+}.css", produces = "text/css")
    public @ResponseBody String getCss(@PathVariable String cssName, HttpServletResponse response) throws IOException {
        final String resourcePath = getSourcePath(CSS_DIR, cssName, "css");
        try (InputStream resourceAsStream = request.getSession().getServletContext().getResourceAsStream(resourcePath)) {
            if (resourceAsStream == null) {
                throw new NoSuchResourceException();
            }

            final StringWriter content = new StringWriter();
            IOUtils.copy(resourceAsStream, content);
            setCacheHeaders(response);
            return content.toString();
        }
    }

    private String getSourcePath(String baseDir, String name, String extention) {
        if (AppUtils.isProd() && !name.endsWith(".min")) {
            // try to get compressed version of file
            final String compressedSource = baseDir + name + ".min." + extention;
            try {
                final URL compressed = request.getSession().getServletContext().getResource(compressedSource);
                if (compressed != null) {
                    return compressedSource;
                }
            } catch (MalformedURLException ignored) {
            }
        }
        return baseDir + name + "." + extention;
    }

    private void setCacheHeaders(HttpServletResponse response) {
        if (AppUtils.isProd()) {
            ServletUtils.setCacheHeaders(response, CACHE_TTL, true);
        }
    }

    @ResponseStatus(HttpStatus.NOT_FOUND)
    public static class NoSuchResourceException extends RuntimeException {
    }
}
